package airportCoordinationMonitor;

import java.util.Iterator;
import java.util.List;
import java.util.concurrent.locks.Lock;

import org.json.JSONObject;

public class PingHandler implements Runnable{

	private int active_port, pasive_port;
	private List<PacketLog> pings;
	private Lock lock;
	private int id;
	private JSONObject ping_msg;
	private SharedProcess active, pasive;
	
	private final int TIMEOUT = 1;
	private static final String COORDINATOR_EXE = "coordinator";

	
	public PingHandler(int ap, int pp, List<PacketLog> p, Lock l, Process act, Process pas)
	{
		active_port = ap;
		pasive_port = pp;
		pings = p;
		lock = l;
		id = (new java.util.Random()).nextInt();
		active = new SharedProcess(act);
		pasive = new SharedProcess(pas);

		ping_msg = new JSONObject();
		try{
			ping_msg.put("type", "PING");
			ping_msg.put("id", 0);
		}catch(Exception e){ System.out.print("FATAL ERROR. Error creating ping message: " + e.getMessage() + "\n"); System.exit(666); }
		
		
	}
	
	public void run()
	{
		Thread or = new Thread(new OutputRedirector(active, pasive));
		or.start();
		
		System.out.print("PingHandler running\n");
		while(true)
		{
			try{
				Thread.sleep(TIMEOUT*60*1000+30*1000);
			}catch(Exception e){ System.out.print("FATAL ERROR. Error trying to sleep PingHandler thread: " + e.getMessage() + "\n"); System.exit(666); }
			
			System.out.print("Sending pings to coordinators...\n");
			
			send_pings();
			check_pings();
		}
	}
	
	private void send_pings()
	{
		try{ ping_msg.put("id", id+1); }catch(Exception e){ System.out.print("FATAL ERROR. Error IDing ping message: " + e.getMessage() + "\n"); System.exit(666); }
		Sender.ping(active_port, ping_msg.toString());
		
		try{ ping_msg.put("id", id+2); }catch(Exception e){ System.out.print("FATAL ERROR. Error IDing ping message: " + e.getMessage() + "\n"); System.exit(666); }
		Sender.ping(pasive_port, ping_msg.toString());
		
		lock.lock();
		pings.add(new PacketLog(id+1, active_port));
		pings.add(new PacketLog(id+2, pasive_port));
		lock.unlock();
		id+=2;
	}
	
	private void check_pings()
	{
		boolean act_killed = false, pas_killed = false;
		lock.lock();
		Iterator<PacketLog> iter = pings.iterator();
		PacketLog packet = null;
		while (iter.hasNext() && (!act_killed || !pas_killed))
		{
			packet = iter.next();
			if (packet.timedout(TIMEOUT))
			{
				if (packet.get_port() == pasive_port)
				{
					if (pas_killed)
					{
						iter.remove();
					}
					else
					{
						System.out.print("Timeout on pasive ping, killing and reinitiating pasive.\n");
						pasive.process().destroy();
						try{
							pasive.set_process(new ProcessBuilder(COORDINATOR_EXE).start());
						}catch(Exception e){ System.out.print("FATAL ERROR executing coordinators: " + e.getMessage() + "\n"); System.exit(666); }
						iter.remove();
						pas_killed = true;
					}
				}
				if (packet.get_port() == active_port)
				{
					if (act_killed)
					{
						iter.remove();
					}
					else
					{
						System.out.print("Timeout on active ping, killing active and reinitiating as pasive, activating pasive.\n");
						active.process().destroy();
						Sender.activate(pasive_port);
						active.set_process(pasive.process());
						try{
							pasive.set_process(new ProcessBuilder(COORDINATOR_EXE).start());
						}catch(Exception e){ System.out.print("FATAL ERROR executing coordinators: " + e.getMessage() + "\n"); System.exit(666); }
						iter.remove();
						act_killed = true;
					}
				}
			}
		}
		lock.unlock();
	}
}
